package com.yao.yaoojbackendgateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 使用 Spring Cloud Gateway 的 Filter 请求拦截器，接受到请求后根据请求的路径判断能否访问
 * 全局过滤器，用于校验请求是否合法
 */
@Component
public class GlobalAuthFilter implements GlobalFilter , Ordered {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();//用这个方法来校验路径是否符合某种规则
    @Override
    //思路：可以拿到每个请求的信息，拿到每个请求的路径来区分允许还是不允许访问
    //继承父类
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();//先拿到请求信息
        String path = serverHttpRequest.getURI().getPath();//获取请求路径
        //判断请求路径是否符合某些规则
        //只要这个路径包含inner，就不允许通过(inner只允许内部调用)
        if(antPathMatcher.match("**/inner/**",path)){
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.FORBIDDEN);
            //给用户返回多余的信息，接收的是反应式的字符串——>异步的（执行到这里的时候，还没有同步得到结果）
            //创建工厂
            DataBufferFactory dataBufferFactory = response.bufferFactory();//缓冲区要和响应值有点关系,不然数据值是不会填充到数据里的
            DataBuffer dataBuffer = dataBufferFactory.wrap("无权限".getBytes(StandardCharsets.UTF_8));
            return response.writeWith(Mono.just(dataBuffer));//filter过滤器接收的就是一个Mono类型的，所以返回值也要是Mono类型，
            // 用just可以创建一个响应式编程的对象(就像用Optional.of可以创建一个Optional对象一样)
        }
        // todo 统一 权限校验
        return chain.filter(exchange);//不拦截的话，让这个请求继续
    }

    /**
     * 优先级提到最高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;//0表示这个优先级是最高的。过滤器也会分优先级
        //如果在后期，有多个拦截器，那么就要区分优先级
        //这个是实现接口访问的拦截器，优先级肯定高
        //这个优先级是高于其他过滤器的，因为其他过滤器是后执行，这个过滤器是先执行
    }
}